﻿using Microsoft.Extensions.Logging;
using System.Net.Sockets;
using TcpJsonService.Core;

namespace TcpJsonService.Fvs
{
    /// <summary>
    /// 协议头
    /// </summary>
    public class ProtocolHead
    {
        /// <summary>
        /// 协议头长度
        /// </summary>
        public const byte HeadSize = 13;
        /// <summary>
        /// 协议头长度
        /// </summary>
        public const byte HeadTag = 0xAB;

        /// <summary>
        /// 协议头识别码
        /// </summary>
        [SerializeIndex(1)]
        public byte Tag { get; set; }

        /// <summary>
        /// 协议编号
        /// </summary>
        [SerializeIndex(2)]
        public ushort Id { get; set; }

        /// <summary>
        /// 协议内容长度
        /// </summary>
        [SerializeIndex(3)]
        public ushort ContentSize { get; set; }

        /// <summary>
        /// 时间戳
        /// </summary>
        [SerializeIndex(4)]
        public long TimeStamp { get; set; }
    }

    /// <summary>
    /// 请求状态协议
    /// </summary>
    public class CollectStatusRequest
    {
        public static ushort Id => 0x0001;
    }

    /// <summary>
    /// 响应状态协议
    /// </summary>
    public class CollectStatusResponse 
    {
        public static ushort Id => 0x0002;

        /// <summary>
        /// 套接字状态集合
        /// </summary>
        [SerializeIndex(1)]
        public List<ControllerStatus> Controllers { get; set; }
    }

    /// <summary>
    /// 转发请求协议
    /// </summary>
    public class ShootRequest
    {
        public static ushort Id => 0x0003;

        /// <summary>
        /// 控制器通道监听的端口
        /// </summary>
        [SerializeIndex(1)] 
        public ushort Port { get; set; }

        /// <summary>
        /// 控制器编号
        /// </summary>
        [SerializeIndex(2)] 
        public int ControllerId { get; set; }

        /// <summary>
        /// 请求协议的编号
        /// </summary>
        [SerializeIndex(3)] 
        public int ProtocolId { get; set; }

        /// <summary>
        /// 请求协议的字节流
        /// </summary>
        [SerializeIndex(4)] 
        public List<byte> Buffer { get; set; }
    }

    /// <summary>
    /// 转发响应协议
    /// </summary>
    public class ShootResponse
    {
        public static ushort Id => 0x0004;

        /// <summary>
        /// 转发结果
        /// </summary>
        [SerializeIndex(1)] 
        public byte Result { get; set; }

        /// <summary>
        /// 控制器通道监听的端口
        /// </summary>
        [SerializeIndex(2)] 
        public ushort Port { get; set; }

        /// <summary>
        /// 控制器编号
        /// </summary>
        [SerializeIndex(3)] 
        public int ControllerId { get; set; }

        /// <summary>
        /// 响应协议的编号
        /// </summary>
        [SerializeIndex(4)] 
        public int ProtocolId { get; set; }

        /// <summary>
        /// 响应协议的字节流
        /// </summary>
        [SerializeIndex(5)] 
        public List<byte> Buffer { get; set; }
    }

    /// <summary>
    /// 转发协议通道
    /// </summary>
    public class RouteChannel : TcpChannel
    {
        /// <summary>
        /// 控制器通道字典,键为监听端口
        /// </summary>
        private readonly Dictionary<int, FvsControllerChannel> _channels;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="port">监听端口</param>
        /// <param name="logger">日志</param>
        /// <param name="channels">控制器通道字典</param>
        public RouteChannel(int port, ILogger logger, Dictionary<int, FvsControllerChannel> channels)
            : base(port, logger)
        {
            _channels = channels;
            foreach (var channel in _channels.Values)
            {
                channel.Responsed += ResponsedEventHandler;
            }
        }

        /// <summary>
        /// 发送内部协议
        /// </summary>
        /// <param name="id">内部协议编号</param>
        /// <param name="content">内部协议数据</param>
        private void SendProtocol(ushort id,object content)
        {
            List<byte> contentBuffer = ByteFormatter.Serialize(content);
            ProtocolHead head = new()
            {
                Tag = ProtocolHead.HeadTag,
                Id = id,
                ContentSize = Convert.ToUInt16(contentBuffer.Count),
                TimeStamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds)
            };
            List<byte> buffer = ByteFormatter.Serialize(head);
            buffer.AddRange(contentBuffer);
            Notice([.. buffer]);
        }

        /// <summary>
        /// 响应事件处理函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ResponsedEventHandler(object sender, GotProtocolEventArgs e)
        {
            ShootResponse response = new()
            {
                Result = Convert.ToByte(SocketResult.Success),
                Port = Convert.ToUInt16(e.Port),
                ControllerId = e.ControllerId,
                ProtocolId = e.ProtocolId,
                Buffer = e.Buffer
            };
            SendProtocol(ShootResponse.Id,response);
            _logger.LogInformation($"=>fvs port:{response.Port} id:{response.ControllerId} protocol:{response.ProtocolId:x2}");
        }

        protected override bool Unpack(Socket socket, List<byte> buffer, ref int offset)
        {
            int head = buffer.FindIndex(offset, b => b == ProtocolHead.HeadTag);
            //未找到协议
            if (head == -1)
            {
                offset += buffer.Count;
                return true;
            }
            else
            {
                int lessSize = buffer.Count - head;
                //长度小于协议头
                if (lessSize < ProtocolHead.HeadSize)
                {
                    offset = head;
                    return false;
                }
                else
                {
                    ProtocolHead protocolHead = new ProtocolHead();
                    int result=ByteFormatter.Deserialize(protocolHead, buffer, head);
                    if (lessSize < protocolHead.ContentSize + ProtocolHead.HeadSize)
                    {
                        offset = head;
                        return false;
                    }
                    else
                    {
                        if (protocolHead.Id == CollectStatusRequest.Id)
                        {
                            CollectStatusResponse response = new()
                            {
                                Controllers = []
                            };
                            foreach (var channel in _channels)
                            {
                                response.Controllers.AddRange(channel.Value.GetStatus());
                            }
                            _logger.LogInformation($"fvs=> protocol size:{response.Controllers.Count}");
                            SendProtocol(CollectStatusResponse.Id, response);
                        }
                        else if (protocolHead.Id == ShootRequest.Id)
                        {
                            ShootRequest request = new();
                            ByteFormatter.Deserialize(request, buffer, head+ProtocolHead.HeadSize);

                            _logger.LogInformation($"fvs=> port:{request.Port} id:{request.ControllerId} protocol:{request.ProtocolId:x2}");
                            if (_channels.TryGetValue(request.Port, out FvsControllerChannel channel))
                            {
                                SocketResult r = channel.SendProtocol(request.ControllerId, [.. request.Buffer]);
                                if (r != SocketResult.Success)
                                {
                                    ShootResponse response = new()
                                    {
                                        Result = Convert.ToByte(r),
                                        Port = request.Port,
                                        ControllerId = request.ControllerId,
                                        ProtocolId = request.ProtocolId
                                    };
                                    SendProtocol(ShootResponse.Id, response);
                                    _logger.LogInformation($"send shoot failed port:{request.Port} id:{request.ControllerId} protocol:{request.ProtocolId:x2}");
                                }
                            }
                            else
                            {
                                ShootResponse response = new()
                                {
                                    Result = Convert.ToByte(SocketResult.NotFoundSocket),
                                    Port = request.Port,
                                    ControllerId = request.ControllerId,
                                    ProtocolId = request.ProtocolId
                                };
                                SendProtocol(ShootResponse.Id, response);
                                _logger.LogInformation($"not found port port:{request.Port} id:{request.ControllerId} protocol:{request.ProtocolId:x2}");
                            }
                        }
                        offset += protocolHead.ContentSize + ProtocolHead.HeadSize;
                        return true;
                    }
                }
            }
        }

    }
}
